/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package cn.ekuma.epos.analysis.businesspartner;

import cn.ekuma.epos.analysis.businesspartner.model.CustomerPaymentsTableModel;
import cn.ekuma.epos.businesslogic.OrderUtil;
import cn.ekuma.epos.datalogic.I_DataLogicERP;
import cn.ekuma.epos.order.model.OrderInfoTableModel;
import cn.ekuma.epos.order.model.OrderRelationTableModel;
import com.openbravo.data.basic.BasicException;
import com.openbravo.data.loader.query.QBF;
import com.openbravo.data.loader.query.QBFCompareEnum;
import com.openbravo.data.loader.query.QBFParameter;
import com.openbravo.format.Formats;
import com.openbravo.bean.erp.OrderRelation;
import com.openbravo.bean.erp.viewbean.CustomerPayment;
import com.openbravo.bean.erp.viewbean.FindOrdersInfo;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.swing.event.EventListenerList;
import javax.swing.tree.TreeNode;
import org.jdesktop.swingx.treetable.AbstractTreeTableModel;
import org.jdesktop.swingx.treetable.TreeTableModel;
import org.jdesktop.swingx.treetable.TreeTableNode;
import prefuse.data.Edge;
import prefuse.data.Graph;
import prefuse.data.Node;
import prefuse.data.Schema;

/**
 *
 * @author Administrator
 */
public class AnalysisModelManager {
    private String curSelectedOrderId;
    private List<FindOrdersInfo> orderList;
    private TreeTableNode rootNode;
    private List<OrderRelation> orderRelationList;
    private OrderInfoTreeTableModel treeTableModel;
    private CustomerPaymentsTableModel customerPaymentsTableModel;

    I_DataLogicERP dlSales;
    private Graph g;
    /** Label data field included in generated Graphs */
    public static final String LABEL = "label";
    public static final String DETAILS= "details";
    public static final String TYPE= "dType";
    public static final String ORDERID="orderId";
    /** Node table schema used for generated Graphs */
    public static final Schema LABEL_SCHEMA = new Schema();
    static {
        LABEL_SCHEMA.addColumn(LABEL, String.class, "");
        LABEL_SCHEMA.addColumn(DETAILS, String.class, "");
        LABEL_SCHEMA.addColumn(TYPE, String.class, "");
        LABEL_SCHEMA.addColumn(ORDERID, String.class, "");
    }

    /** List of listeners */
    protected EventListenerList listenerList = new EventListenerList();

    public AnalysisModelManager(I_DataLogicERP dlSales) {
        this.dlSales=dlSales; 
        curSelectedOrderId=null;
        orderList=new ArrayList();
        orderRelationList=new ArrayList();
        rootNode=buildPermissionRootNode(orderList);
        treeTableModel=new OrderInfoTreeTableModel(rootNode);
        g=new Graph();
        g.getNodeTable().addColumns(LABEL_SCHEMA);
        customerPaymentsTableModel=new CustomerPaymentsTableModel();
        
    }
    String[] orderRelationFields=new String[]{"T.ORDERID", "T.DEFINETYPEREF", "T.ORDERTYPE", "T.CURDATE", "T.CURDATE", "P.NAME", "C.NAME", "T.LOCATIONREF", "T.TOTALPRICE"};
    String[] customerPaymentFields= new String[]{"T.ORDERID", "T.DEFINETYPEREF", "T.ORDERTYPE", "T.CURDATE", "T.CURDATE", "P.NAME", "C.NAME", "T.LOCATIONREF", "T.TOTALPRICE"};
    public void query(Object filter) throws BasicException{
        List<CustomerPayment> payList;
        orderList = dlSales.listOrderInfoByAnlysis(filter);
        Object[] filterProp=(Object[])filter;
        QBF qbf=QBF.c();
        for(int i=0;i<filterProp.length;i=i+2)
            if(filterProp[i]!=QBFCompareEnum.COMP_NONE)
                qbf.and(new QBFParameter(orderRelationFields[i/2],(QBFCompareEnum) filterProp[i],filterProp[i+1]));
        orderRelationList = dlSales.query(OrderRelation.class, qbf.build());

        payList=dlSales.query(CustomerPayment.class,  qbf.build());

         curSelectedOrderId=null;
         rootNode=buildPermissionRootNode(orderList);
         treeTableModel.reflush();
        //buildGraph();
        //buildCustomerPayments(payList);
    }

    private void buildCustomerPayments (List<CustomerPayment> payList){
        List<CustomerPaymentsEntry> customerPayments=new ArrayList<CustomerPaymentsEntry>();
        ArrayList<String> orderTypeColumn=new ArrayList<String>();
        ArrayList<String> payTypeColumn=new ArrayList<String>();
        for(CustomerPayment p:payList){
            if(!orderTypeColumn.contains(p.getOrderType()))
                orderTypeColumn.add(p.getOrderType());
            if(!payTypeColumn.contains(p.getPaymentType()))
                payTypeColumn.add(p.getPaymentType());
           getCustomerPaymentsEntryByName(customerPayments,p.getName()).addCustomerPayment(p);
        }
        customerPaymentsTableModel.resert(customerPayments, orderTypeColumn, payTypeColumn);
    }

    private CustomerPaymentsEntry getCustomerPaymentsEntryByName(List<CustomerPaymentsEntry> customerPayments,String name){
        for(CustomerPaymentsEntry e:customerPayments){
            if(e.getName().equalsIgnoreCase(name))
                return e;
        }
        CustomerPaymentsEntry selected=new CustomerPaymentsEntry(name);
        customerPayments.add(selected);
        return selected;
    }

    private void buildGraph(){
        g=new Graph();
        g.getNodeTable().addColumns(LABEL_SCHEMA);
        String label;
        ArrayList<Node> list=new ArrayList<Node>();
        for(FindOrdersInfo o:orderList){
            Node newNode=g.addNode();
            label=o.getCustomer()==null?"":o.getCustomer();
            label=o.getDefineType()+"<"+o.getOrderId()+">"+label+"*"+o.getTotalPrice();
            newNode.set(LABEL,label);
            newNode.set(DETAILS, OrderInfoTableModel.getOrderInfoDescription(o));
            newNode.set(TYPE,LABEL);
            newNode.set(ORDERID, o.getOrderId());
            list.add(newNode);
        }
        for(int i=0;i<orderList.size();i++){
            for(int j=0;j<orderRelationList.size();j++){
                if(orderList.get(i).getId().equalsIgnoreCase(orderRelationList.get(j).getRefId())){
                    int jj=getOrdersIndex(orderRelationList.get(j).getSuperID());
                    Edge edg=g.addEdge(list.get(i), list.get(jj));
                   
                }
            }
        }
    }

    public CustomerPaymentsTableModel getCustomerPaymentsTableModel() {
        return customerPaymentsTableModel;
    }

    public Graph getGraph(){
        return g;
    }

    private int getOrdersIndex(String id){
        for(int i=0;i<orderList.size();i++){
            if(orderList.get(i).getId().equalsIgnoreCase(id)){
                return i;
            }
        }
        return -1;
    }


    private TreeTableNode buildPermissionRootNode(List<FindOrdersInfo> orderList) {
        OrderTypeTreeTableNode temp = new OrderTypeTreeTableNode(null, "root");
        OrderTypeTreeTableNode orderTypeTemp = null;
        OrderInfoTreeTableNode orderInfoTemp = null;
        for (FindOrdersInfo o : orderList) {
            String orderTypeName = o.getDefineType();
            orderTypeTemp = findOrderTypeByName(temp.getChildren(), orderTypeName);
            if (orderTypeTemp == null) {
                orderTypeTemp = new OrderTypeTreeTableNode(temp, orderTypeName);
                temp.add(orderTypeTemp);
            }
            orderInfoTemp = new OrderInfoTreeTableNode(orderTypeTemp, o);
            orderInfoTemp.setRelationInfo(getOrderRelationListByOrderInfo(o.getId()));
            orderTypeTemp.add(orderInfoTemp);
        }
        return temp;
    }

    public List<OrderRelation> getOrderRelationListByOrderInfo(String id){
        List<OrderRelation> ret=new ArrayList<OrderRelation>();
        for(OrderRelation temp:orderRelationList){
            if(temp.getSuperID().equalsIgnoreCase(id))
                ret.add(temp);
        }
        return ret;
    }

    public List<OrderRelation> getOrderRelationListToByOrderId(String id){
        List<OrderRelation> ret=new ArrayList<OrderRelation>();
        for(OrderRelation temp:orderRelationList){
            if(temp.getRefId().equalsIgnoreCase(id))
                ret.add(temp);
        }
        return ret;
    }

      private OrderTypeTreeTableNode findOrderTypeByName(List<TreeTableNode> nodes, String groupName) {
        for (TreeTableNode node : nodes) {
            if ((node instanceof OrderTypeTreeTableNode) && ((OrderTypeTreeTableNode) node).getOrderTypeName().equalsIgnoreCase(groupName)) {
                return (OrderTypeTreeTableNode) node;
            }
        }
        return null;
    }

    public void addOrderChangedListener(OrderInfoChangedListener l){
        listenerList.add(OrderInfoChangedListener.class, l);
    }

    public void removeOrderChangeListener(OrderInfoChangedListener l){
       listenerList.remove(OrderInfoChangedListener.class, l);
   }

    public OrderInfoChangedListener[] getOrderChangedListeners() {
        return (OrderInfoChangedListener[])listenerList.getListeners(OrderInfoChangedListener.class);
    }

     public void fireOrderChanged(Object src,String id) {
        for(FindOrdersInfo o:orderList){
            if(o.getOrderId().equalsIgnoreCase(id)){
                 curSelectedOrderId=o.getId();
                 break;
            }
        }
	// Guaranteed to return a non-null array
	Object[] listeners = listenerList.getListenerList();
	// Process the listeners last to first, notifying
	// those that are interested in this event
	for (int i = listeners.length-2; i>=0; i-=2) {
	    if (listeners[i]==OrderInfoChangedListener.class) {
		((OrderInfoChangedListener)listeners[i+1]).orderInfoChanged(src, id);
	    }
    }
    }

     public TreeTableModel getTreeTableModel(){
         return treeTableModel;
     }

    class OrderInfoTreeTableModel extends AbstractTreeTableModel {


        public OrderInfoTreeTableModel(TreeTableNode root) {
            super(root);
        }

        @Override
        public String getColumnName(int column) {
            if(column==OrderInfoTableModel.TABLECOLUMNS_OrderInfo.length)
                return OrderRelationTableModel.ORDERREFNOTES;
           return OrderInfoTableModel.TABLECOLUMNS_OrderInfo[column];
        }

        @Override
        public int getColumnCount() {
            return OrderInfoTableModel.TABLECOLUMNS_OrderInfo.length+1;
        }

        @Override
        public Object getValueAt(Object node, int column) {
            if (column < 0 || column >= getColumnCount()) {
                throw new IllegalArgumentException("column must be a valid index");
            }
            TreeTableNode ttn = (TreeTableNode) node;
            if (column >= ttn.getColumnCount()) {
                return null;
            }
            return ttn.getValueAt(column);
        }

        @Override
        public Object getChild(Object parent, int index) {
            return ((TreeTableNode) parent).getChildAt(index);
        }

        @Override
        public int getChildCount(Object parent) {
            return ((TreeTableNode) parent).getChildCount();
        }

        @Override
        public int getIndexOfChild(Object parent, Object child) {
            return ((TreeTableNode) parent).getIndex((TreeTableNode) child);
        }

        public void reflush() {
            super.root=rootNode;
            modelSupport.fireNewRoot();
        }

        public TreeTableNode[] getPathToRoot(TreeTableNode aNode) {
            List<TreeTableNode> path = new ArrayList<TreeTableNode>();
            TreeTableNode node = aNode;

            while (node != root) {
                path.add(0, node);
                node = (TreeTableNode) node.getParent();
            }
            if (node == root) {
                path.add(0, node);
            }
            return path.toArray(new TreeTableNode[0]);
        }
    }

    class OrderInfoTreeTableNode implements TreeTableNode {
        TreeTableNode parent;
        FindOrdersInfo orderInfo;
        List<OrderRelation> relationInfoList;

        public OrderInfoTreeTableNode(TreeTableNode parent, FindOrdersInfo orderInfo) {
            this.parent = parent;
            this.orderInfo = orderInfo;
        }

        @Override
        public Enumeration<? extends TreeTableNode> children() {
            return null;
        }

        @Override
        public Object getValueAt(int i) {
            switch(i){
                case 0:
                    return orderInfo.getOrderId();
                case 1:
                    return orderInfo.getDefineType();
                case 2:
                    return orderInfo.getOrderType()==0?OrderUtil.ORDERTYPE_Normal:OrderUtil.ORDERTYPE_Revoerse;
                case 3:
                    return Formats.TIMESTAMP.formatValue(orderInfo.getDate());
                case 4:
                    return orderInfo.getCustomer()==null?"":orderInfo.getCustomer();
                case 5:
                     return orderInfo.getLocation();
                case 6:
                     return orderInfo.getName();
                case 7:
                      return Formats.CURRENCY.formatValue(orderInfo.getTotalPrice());
                case 8:
                      return orderInfo.getMemo();
                case 9:
                      return orderInfo.getCurrentState();
                case 10:
                      return orderInfo.getM_sResponse();
                case 11:
                      return orderInfo.getLocationRef1();
                case 12:
                      return Formats.PERCENT.formatValue(orderInfo.getM_dPriceRate());
                case 13:
                    return getOrderRefMomo();
            }
            return null;
        }


        public String getOrderRefMomo(){
            for(OrderRelation oref:relationInfoList){
                if(curSelectedOrderId!=null&&oref.getRefId().equalsIgnoreCase(curSelectedOrderId))
                    return oref.getMemo();
            }
            return null;
        }

        @Override
        public TreeTableNode getChildAt(int i) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public int getColumnCount() {
            return OrderInfoTableModel.TABLECOLUMNS_OrderInfo.length+1;
        }

        @Override
        public TreeTableNode getParent() {
            return this.parent;
        }

        @Override
        public Object getUserObject() {
            return orderInfo;
        }

        @Override
        public void setUserObject(Object o) {
        }

        @Override
        public int getChildCount() {
            return 0;
        }

        @Override
        public int getIndex(TreeNode node) {
            return 0;
        }

        @Override
        public boolean getAllowsChildren() {
            return false;
        }

        @Override
        public boolean isLeaf() {
            return true;
        }

        public FindOrdersInfo getOrderInfo() {
            return orderInfo;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof OrderInfoTreeTableNode) {
                OrderInfoTreeTableNode temp = (OrderInfoTreeTableNode) obj;
                return this.orderInfo.equals(temp.getOrderInfo());
            } else if (obj instanceof FindOrdersInfo) {
                FindOrdersInfo temp = (FindOrdersInfo) obj;
                return this.orderInfo.equals(temp);
            }
            return false;
        }

        private void setRelationInfo(List<OrderRelation> orderRelationList) {
            this.relationInfoList=orderRelationList;
        }

        public boolean isEditable(int i) {
            return false;
        }

        public void setValueAt(Object o, int i) {
        }
    }

    class OrderTypeTreeTableNode implements TreeTableNode {
        TreeTableNode parent;
        List<TreeTableNode> children;
        String orderTypeName;
        

        public OrderTypeTreeTableNode(TreeTableNode parent, String orderTypeName) {
            this.parent = parent;
            this.orderTypeName = orderTypeName;
            children = new ArrayList<TreeTableNode>();
        }

        public void add(FindOrdersInfo orderInfo) {
            children.add(new OrderInfoTreeTableNode(this, orderInfo));
        }

        public void add(TreeTableNode childNode) {
            children.add(childNode);
        }

        @Override
        public Enumeration<? extends TreeTableNode> children() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public Object getValueAt(int i) {
            switch (i) {
                case 0:
                    return orderTypeName;
            }
            return null;
        }

        @Override
        public TreeTableNode getChildAt(int i) {
            return children.get(i);
        }

        @Override
        public int getColumnCount() {
            return OrderInfoTableModel.TABLECOLUMNS_OrderInfo.length;
        }

        @Override
        public TreeTableNode getParent() {
            return parent;
        }

        @Override
        public boolean isEditable(int i) { 
            return false;
        }

        @Override
        public void setValueAt(Object o, int i) {
           
        }

        @Override
        public Object getUserObject() {
            return children;
        }

        @Override
        public void setUserObject(Object o) {
        }

        @Override
        public int getChildCount() {
            return children.size();
        }

        @Override
        public int getIndex(TreeNode node) {
            return children.indexOf(node);
        }

        @Override
        public boolean getAllowsChildren() {
            return !children.isEmpty();
        }

        @Override
        public boolean isLeaf() {
            return false;
        }

        public String getOrderTypeName() {
            return orderTypeName;
        }

        public List<TreeTableNode> getChildren() {
            return children;
        }
    }
}
